/*
 * Copyright (C) 2011 Nicola Bonzanni
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package nl.vu.few.ibivu.jlemon;

import java.util.Map;

import nl.vu.few.ibivu.jlemon.concepts.Arc;
import nl.vu.few.ibivu.jlemon.concepts.Graph;
import nl.vu.few.ibivu.jlemon.concepts.Node;

//FIXME cycles not handled!!!
public class PredMapPath<N extends Node & Comparable<N>, A extends Arc & Comparable<A>> extends
		AbstractPath<A> {

	Graph<N, A> graph;
	Map<N, A> predMap;
	N target;

	public PredMapPath(Graph<N, A> graph, Map<N, A> predMap, N target) {
		super();
		this.graph = graph;
		this.predMap = predMap;
		this.target = target;
	}

	@Override
	public int length() {
		int len = 0;
		N node = target;
		A arc;
		while ((arc = predMap.get(node)) != null) {
			node = graph.source(arc);
			++len;
		}
		return len;
	}

	@Override
	public boolean empty() {
		return predMap.get(target) == null;
	}

	@Override
	public A back() {
		return predMap.get(target);
	}

	@Override
	public A nth(int n) {
		N node = target;
		A arc;
		int i = length();
		while ((arc = predMap.get(node)) != null && (--i > n)) {
			node = graph.source(arc);
		}
		return arc;
	}

	@Override
	public PredMapPathIterator nthIterator(int n) {
		return new PredMapPathIterator(n);
	}
	
	public PredMapPathIterator reverseIterator() {
		return new PredMapPathIterator(true);
	}
	
	public class PredMapPathIterator extends PathIterator<A> {
	
		public PredMapPathIterator(boolean reverse) {
			super(PredMapPath.this, reverse);
		}
		
		public PredMapPathIterator(int n) {
			super(PredMapPath.this, n);
		}

		@Override
		protected A computePrevious() {
			return predMap.get(graph.source(current));
		}
		
		@Override
		protected A computeNext() {
			N node = target;
			A arc;
			A nextArc = null;
			while ((arc = predMap.get(node)) != null) {
				node = graph.source(arc);
				if (arc.equals(current)) {
					break;
				}
				nextArc = arc;
			}
			return nextArc;
		}
	}

}
